#pragma once
#ifndef FILE_UTIL_HPP
#define FILE_UTIL_HPP

#include <fstream>
#include <sstream>

namespace Utility {

/*
 * Reference from cocos2dx FileUtil
 * This is a buffer interface
 * provide base file buffer resize functional
 * and get buffer contents functional
 */
class IFileBuffer {
public:
  virtual ~IFileBuffer() noexcept {}
  virtual void resize(size_t size) = 0;
  virtual size_t getNumBytes() const = 0;
  virtual void *buffer() const = 0;
};

template <class T> class FileBufferAdaptor {};

/*
 * File Buffer Adaptor
 *
 */
template <class CharT, class Traits, class Allocator>
class FileBufferAdaptor<std::basic_string<CharT, Traits, Allocator>>
    : public IFileBuffer {
private:
  using FileBufferType = std::basic_string<CharT, Traits, Allocator>;

public:
  FileBufferAdaptor(FileBufferType *buffer) : _buffer(buffer) {}

  void resize(size_t size) override {
    _buffer->resize((size + sizeof(CharT) - 1) / sizeof(CharT));
  }

  void *buffer() const override {
    if (_buffer->empty())
      return nullptr;
    else
      return _buffer->data();
  }

  size_t getNumBytes() const override { return _buffer->size() * sizeof(CharT); }

private:
  FileBufferType *_buffer;
};

/*
 * File phaser, an interface to reading file contents
 *
 *
 */
class FilePhaser {
public:
  static FilePhaser &GetInstance();
  template <typename T, typename Enable = typename std::enable_if<std::is_base_of<
                            IFileBuffer, FileBufferAdaptor<T>>::value>::type>
  bool GetContents(const std::string &fileName, T *buf);
  virtual bool GetContents(const std::string &fileName, IFileBuffer *buf);

  std::string GetStringFromFile(const std::string &fileName);

protected:
  FilePhaser() {}
};

} // namespace Utility

#endif